home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / xmu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-24  |  16.5 KB  |  564 lines

  1. /* This file contains compatibility routines for systems without Xmu.
  2.  * You would be better served by installing Xmu on your machine or
  3.  * yelling at your vendor to ship it.
  4.  */
  5.  
  6. /* XEmacs changes: rindex -> strrchr */
  7.  
  8. /* Synched up with: Not in FSF. */
  9.  
  10. #include <config.h>
  11.  
  12. #ifndef HAVE_XMU
  13. /*
  14.  * Copyright 1989 Massachusetts Institute of Technology
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software and its
  17.  * documentation for any purpose and without fee is hereby granted, provided
  18.  * that the above copyright notice appear in all copies and that both that
  19.  * copyright notice and this permission notice appear in supporting
  20.  * documentation, and that the name of M.I.T. not be used in advertising
  21.  * or publicity pertaining to distribution of the software without specific,
  22.  * written prior permission.  M.I.T. makes no representations about the
  23.  * suitability of this software for any purpose.  It is provided "as is"
  24.  * without express or implied warranty.
  25.  *
  26.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  28.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  29.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  30.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  31.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  32.  */
  33. #include <X11/cursorfont.h>
  34. #include <X11/Xos.h>
  35. #include <X11/Xlib.h>
  36. #include <X11/Xutil.h>
  37. #include <X11/Intrinsic.h>
  38.  
  39. /* for XmuCopyISOLatin1Lowered */
  40. #define XK_LATIN1
  41. #include <X11/keysymdef.h>
  42. #undef XK_LATIN1
  43.  
  44. #if (XtSpecificationRelease == 5)
  45. /*
  46.  * Don't know why, but this works with X11R5, not X11R4.
  47.  * Anyway, _XExtension is defined in Xlib.h in X11R4, so we do not need
  48.  * Xlibint in that case...
  49.  */
  50. #include <X11/Xlibint.h>
  51. #endif
  52. #include <X11/Xproto.h>
  53. #include <stdio.h>
  54. #include <ctype.h>
  55.  
  56.  
  57. int XmuCursorNameToIndex (const char *name)
  58. {
  59.     static const struct _CursorName {
  60.     const char    *name;
  61.     unsigned int    shape;
  62.     } cursor_names[] = {
  63.             {"x_cursor",        XC_X_cursor},
  64.             {"arrow",        XC_arrow},
  65.             {"based_arrow_down",    XC_based_arrow_down},
  66.             {"based_arrow_up",    XC_based_arrow_up},
  67.             {"boat",        XC_boat},
  68.             {"bogosity",        XC_bogosity},
  69.             {"bottom_left_corner",    XC_bottom_left_corner},
  70.             {"bottom_right_corner",    XC_bottom_right_corner},
  71.             {"bottom_side",        XC_bottom_side},
  72.             {"bottom_tee",        XC_bottom_tee},
  73.             {"box_spiral",        XC_box_spiral},
  74.             {"center_ptr",        XC_center_ptr},
  75.             {"circle",        XC_circle},
  76.             {"clock",        XC_clock},
  77.             {"coffee_mug",        XC_coffee_mug},
  78.             {"cross",        XC_cross},
  79.             {"cross_reverse",    XC_cross_reverse},
  80.             {"crosshair",        XC_crosshair},
  81.             {"diamond_cross",    XC_diamond_cross},
  82.             {"dot",            XC_dot},
  83.             {"dotbox",        XC_dotbox},
  84.             {"double_arrow",    XC_double_arrow},
  85.             {"draft_large",        XC_draft_large},
  86.             {"draft_small",        XC_draft_small},
  87.             {"draped_box",        XC_draped_box},
  88.             {"exchange",        XC_exchange},
  89.             {"fleur",        XC_fleur},
  90.             {"gobbler",        XC_gobbler},
  91.             {"gumby",        XC_gumby},
  92.             {"hand1",        XC_hand1},
  93.             {"hand2",        XC_hand2},
  94.             {"heart",        XC_heart},
  95.             {"icon",        XC_icon},
  96.             {"iron_cross",        XC_iron_cross},
  97.             {"left_ptr",        XC_left_ptr},
  98.             {"left_side",        XC_left_side},
  99.             {"left_tee",        XC_left_tee},
  100.             {"leftbutton",        XC_leftbutton},
  101.             {"ll_angle",        XC_ll_angle},
  102.             {"lr_angle",        XC_lr_angle},
  103.             {"man",            XC_man},
  104.             {"middlebutton",    XC_middlebutton},
  105.             {"mouse",        XC_mouse},
  106.             {"pencil",        XC_pencil},
  107.             {"pirate",        XC_pirate},
  108.             {"plus",        XC_plus},
  109.             {"question_arrow",    XC_question_arrow},
  110.             {"right_ptr",        XC_right_ptr},
  111.             {"right_side",        XC_right_side},
  112.             {"right_tee",        XC_right_tee},
  113.             {"rightbutton",        XC_rightbutton},
  114.             {"rtl_logo",        XC_rtl_logo},
  115.             {"sailboat",        XC_sailboat},
  116.             {"sb_down_arrow",    XC_sb_down_arrow},
  117.             {"sb_h_double_arrow",    XC_sb_h_double_arrow},
  118.             {"sb_left_arrow",    XC_sb_left_arrow},
  119.             {"sb_right_arrow",    XC_sb_right_arrow},
  120.             {"sb_up_arrow",        XC_sb_up_arrow},
  121.             {"sb_v_double_arrow",    XC_sb_v_double_arrow},
  122.             {"shuttle",        XC_shuttle},
  123.             {"sizing",        XC_sizing},
  124.             {"spider",        XC_spider},
  125.             {"spraycan",        XC_spraycan},
  126.             {"star",        XC_star},
  127.             {"target",        XC_target},
  128.             {"tcross",        XC_tcross},
  129.             {"top_left_arrow",    XC_top_left_arrow},
  130.             {"top_left_corner",    XC_top_left_corner},
  131.             {"top_right_corner",    XC_top_right_corner},
  132.             {"top_side",        XC_top_side},
  133.             {"top_tee",        XC_top_tee},
  134.             {"trek",        XC_trek},
  135.             {"ul_angle",        XC_ul_angle},
  136.             {"umbrella",        XC_umbrella},
  137.             {"ur_angle",        XC_ur_angle},
  138.             {"watch",        XC_watch},
  139.             {"xterm",        XC_xterm},
  140.     };
  141.     const struct _CursorName *table;
  142.     int i;
  143.     char tmp[40];
  144.     
  145.     if (strlen (name) >= sizeof tmp) return -1;
  146.     for (i=0; i<strlen(name); i++) 
  147.         if (isupper((unsigned char) name[i]))
  148.             tmp[i] = tolower((unsigned char) name[i]);
  149.         else
  150.             tmp[i] = name[i];
  151.     tmp[i] = 0;
  152.  
  153.     for (i=0, table=cursor_names; i < XtNumber(cursor_names); i++, table++ ) {
  154.     if (strcmp(tmp, table->name) == 0) return table->shape;
  155.     }
  156.  
  157.     return -1;
  158. }
  159.  
  160.  
  161. /*
  162.  * Based on an optimized version provided by Jim Becker, Auguest 5, 1988.
  163.  */
  164.  
  165.  
  166. #define MAX_SIZE 255
  167.  
  168. /* shared data for the image read/parse logic */
  169. static short hexTable[256];        /* conversion value */
  170. static Bool initialized = False;    /* easier to fill in at run time */
  171.  
  172.  
  173. /*
  174.  *    Table index for the hex values. Initialized once, first time.
  175.  *    Used for translation value or delimiter significance lookup.
  176.  */
  177. static void initHexTable()
  178. {
  179.     /*
  180.      * We build the table at run time for several reasons:
  181.      *
  182.      *     1.  portable to non-ASCII machines.
  183.      *     2.  still reentrant since we set the init flag after setting table.
  184.      *     3.  easier to extend.
  185.      *     4.  less prone to bugs.
  186.      */
  187.     hexTable['0'] = 0;    hexTable['1'] = 1;
  188.     hexTable['2'] = 2;    hexTable['3'] = 3;
  189.     hexTable['4'] = 4;    hexTable['5'] = 5;
  190.     hexTable['6'] = 6;    hexTable['7'] = 7;
  191.     hexTable['8'] = 8;    hexTable['9'] = 9;
  192.     hexTable['A'] = 10;    hexTable['B'] = 11;
  193.     hexTable['C'] = 12;    hexTable['D'] = 13;
  194.     hexTable['E'] = 14;    hexTable['F'] = 15;
  195.     hexTable['a'] = 10;    hexTable['b'] = 11;
  196.     hexTable['c'] = 12;    hexTable['d'] = 13;
  197.     hexTable['e'] = 14;    hexTable['f'] = 15;
  198.  
  199.     /* delimiters of significance are flagged w/ negative value */
  200.     hexTable[' '] = -1;    hexTable[','] = -1;
  201.     hexTable['}'] = -1;    hexTable['\n'] = -1;
  202.     hexTable['\t'] = -1;
  203.     
  204.     initialized = True;
  205. }
  206.  
  207. /*
  208.  *    read next hex value in the input stream, return -1 if EOF
  209.  */
  210. static int NextInt (fstream)
  211.     FILE *fstream;
  212. {
  213.     int    ch;
  214.     int    value = 0;
  215.     int gotone = 0;
  216.     int done = 0;
  217.     
  218.     /* loop, accumulate hex value until find delimiter  */
  219.     /* skip any initial delimiters found in read stream */
  220.  
  221.     while (!done) {
  222.     ch = getc(fstream);
  223.     if (ch == EOF) {
  224.         value    = -1;
  225.         done++;
  226.     } else {
  227.         /* trim high bits, check type and accumulate */
  228.         ch &= 0xff;
  229.         if (isascii(ch) && isxdigit(ch)) {
  230.         value = (value << 4) + hexTable[ch];
  231.         gotone++;
  232.         } else if ((hexTable[ch]) < 0 && gotone)
  233.           done++;
  234.     }
  235.     }
  236.     return value;
  237. }
  238.  
  239.  
  240. /*
  241.  * The data returned by the following routine is always in left-most byte
  242.  * first and left-most bit first.  If it doesn't return BitmapSuccess then
  243.  * its arguments won't have been touched.  This routine should look as much
  244.  * like the Xlib routine XReadBitmapfile as possible.
  245.  */
  246. int XmuReadBitmapData (fstream, width, height, datap, x_hot, y_hot)
  247.     FILE *fstream;            /* handle on file  */
  248.     unsigned int *width, *height;    /* RETURNED */
  249.     unsigned char **datap;        /* RETURNED */
  250.     int *x_hot, *y_hot;            /* RETURNED */
  251. {
  252.     unsigned char *data = NULL;        /* working variable */
  253.     char line[MAX_SIZE];        /* input line from file */
  254.     int size;                /* number of bytes of data */
  255.     char name_and_type[MAX_SIZE];    /* an input line */
  256.     char *type;                /* for parsing */
  257.     int value;                /* from an input line */
  258.     int version10p;            /* boolean, old format */
  259.     int padding;            /* to handle alignment */
  260.     int bytes_per_line;            /* per scanline of data */
  261.     unsigned int ww = 0;        /* width */
  262.     unsigned int hh = 0;        /* height */
  263.     int hx = -1;            /* x hotspot */
  264.     int hy = -1;            /* y hotspot */
  265.  
  266. #ifndef Xmalloc
  267. #define Xmalloc(size) malloc(size)
  268. #endif
  269.  
  270.     /* first time initialization */
  271.     if (initialized == False) initHexTable();
  272.  
  273.     /* error cleanup and return macro    */
  274. #define    RETURN(code) { if (data) free (data); return code; }
  275.  
  276.     while (fgets(line, MAX_SIZE, fstream)) {
  277.     if (strlen(line) == MAX_SIZE-1) {
  278.         RETURN (BitmapFileInvalid);
  279.     }
  280.     if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
  281.         if (!(type = strrchr(name_and_type, '_')))
  282.           type = name_and_type;
  283.         else
  284.           type++;
  285.  
  286.         if (!strcmp("width", type))
  287.           ww = (unsigned int) value;
  288.         if (!strcmp("height", type))
  289.           hh = (unsigned int) value;
  290.         if (!strcmp("hot", type)) {
  291.         if (type-- == name_and_type || type-- == name_and_type)
  292.           continue;
  293.         if (!strcmp("x_hot", type))
  294.           hx = value;
  295.         if (!strcmp("y_hot", type))
  296.           hy = value;
  297.         }
  298.         continue;
  299.     }
  300.     
  301.     if (sscanf(line, "static short %s = {", name_and_type) == 1)
  302.       version10p = 1;
  303.     else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
  304.       version10p = 0;
  305.     else if (sscanf(line, "static char %s = {", name_and_type) == 1)
  306.       version10p = 0;
  307.     else
  308.       continue;
  309.  
  310.     if (!(type = strrchr(name_and_type, '_')))
  311.       type = name_and_type;
  312.     else
  313.       type++;
  314.  
  315.     if (strcmp("bits[]", type))
  316.       continue;
  317.     
  318.     if (!ww || !hh)
  319.       RETURN (BitmapFileInvalid);
  320.  
  321.     if ((ww % 16) && ((ww % 16) < 9) && version10p)
  322.       padding = 1;
  323.     else
  324.       padding = 0;
  325.  
  326.     bytes_per_line = (ww+7)/8 + padding;
  327.  
  328.     size = bytes_per_line * hh;
  329.     data = (unsigned char *) Xmalloc ((unsigned int) size);
  330.     if (!data) 
  331.       RETURN (BitmapNoMemory);
  332.  
  333.     if (version10p) {
  334.         unsigned char *ptr;
  335.         int bytes;
  336.  
  337.         for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
  338.         if ((value = NextInt(fstream)) < 0)
  339.           RETURN (BitmapFileInvalid);
  340.         *(ptr++) = value;
  341.         if (!padding || ((bytes+2) % bytes_per_line))
  342.           *(ptr++) = value >> 8;
  343.         }
  344.     } else {
  345.         unsigned char *ptr;
  346.         int bytes;
  347.  
  348.         for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
  349.         if ((value = NextInt(fstream)) < 0) 
  350.           RETURN (BitmapFileInvalid);
  351.         *ptr=value;
  352.         }
  353.     }
  354.     break;
  355.     }                    /* end while */
  356.  
  357.     if (data == NULL) {
  358.     RETURN (BitmapFileInvalid);
  359.     }
  360.  
  361.     *datap = data;
  362.     data = NULL;
  363.     *width = ww;
  364.     *height = hh;
  365.     if (x_hot) *x_hot = hx;
  366.     if (y_hot) *y_hot = hy;
  367.  
  368.     RETURN (BitmapSuccess);
  369. }
  370.  
  371.  
  372. #if NeedFunctionPrototypes
  373. int XmuReadBitmapDataFromFile (CONST char *filename, unsigned int *width, 
  374.                    unsigned int *height, unsigned char **datap,
  375.                    int *x_hot, int *y_hot)
  376. #else
  377. int XmuReadBitmapDataFromFile (filename, width, height, datap, x_hot, y_hot)
  378.     char *filename;
  379.     unsigned int *width, *height;    /* RETURNED */
  380.     unsigned char **datap;        /* RETURNED */
  381.     int *x_hot, *y_hot;            /* RETURNED */
  382. #endif
  383. {
  384.     FILE *fstream;
  385.     int status;
  386.  
  387.     if ((fstream = fopen (filename, "r")) == NULL) {
  388.     return BitmapOpenFailed;
  389.     }
  390.     status = XmuReadBitmapData (fstream, width, height, datap, x_hot, y_hot);
  391.     fclose (fstream);
  392.     return status;
  393. }
  394.  
  395. /*
  396.  * XmuPrintDefaultErrorMessage - print a nice error that looks like the usual 
  397.  * message.  Returns 1 if the caller should consider exitting else 0.
  398.  */
  399. int XmuPrintDefaultErrorMessage (dpy, event, fp)
  400.     Display *dpy;
  401.     XErrorEvent *event;
  402.     FILE *fp;
  403. {
  404.     char buffer[BUFSIZ];
  405.     char mesg[BUFSIZ];
  406.     char number[32];
  407.     char *mtype = "XlibMessage";
  408.     _XExtension *ext = (_XExtension *)NULL;
  409.     XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
  410.     XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
  411.     (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
  412.     XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 
  413.     mesg, BUFSIZ);
  414.     (void) fprintf(fp, mesg, event->request_code);
  415.     if (event->request_code < 128) {
  416.     sprintf(number, "%d", event->request_code);
  417.     XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
  418.     } else {
  419.     /* XXX this is non-portable */
  420.     for (ext = dpy->ext_procs;
  421.          ext && (ext->codes.major_opcode != event->request_code);
  422.          ext = ext->next)
  423.       ;
  424.     if (ext)
  425.         strcpy(buffer, ext->name);
  426.     else
  427.         buffer[0] = '\0';
  428.     }
  429.     (void) fprintf(fp, " (%s)", buffer);
  430.     fputs("\n  ", fp);
  431. #if (XtSpecificationRelease == 5)
  432.     if (event->request_code >= 128) {
  433.     XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
  434.                   mesg, BUFSIZ);
  435.     (void) fprintf(fp, mesg, event->minor_code);
  436.     if (ext) {
  437.         sprintf(mesg, "%s.%d", ext->name, event->minor_code);
  438.         XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
  439.         (void) fprintf(fp, " (%s)", buffer);
  440.     }
  441.     fputs("\n  ", fp);
  442.     }
  443.     if (event->error_code >= 128) {
  444.     /* let extensions try to print the values */
  445.     /* XXX this is non-portable code */
  446.     for (ext = dpy->ext_procs; ext; ext = ext->next) {
  447.         if (ext->error_values)
  448.         (*ext->error_values)(dpy, event, fp);
  449.     }
  450.     /* the rest is a fallback, providing a simple default */
  451.     /* kludge, try to find the extension that caused it */
  452.     buffer[0] = '\0';
  453.     for (ext = dpy->ext_procs; ext; ext = ext->next) {
  454.         if (ext->error_string) 
  455.         (*ext->error_string)(dpy, event->error_code, &ext->codes,
  456.                      buffer, BUFSIZ);
  457.         if (buffer[0])
  458.         break;
  459.     }    
  460.     if (buffer[0])
  461.         sprintf(buffer, "%s.%d", ext->name,
  462.             event->error_code - ext->codes.first_error);
  463.     else
  464.         strcpy(buffer, "Value");
  465.     XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
  466.     if (*mesg) {
  467.         (void) fprintf(fp, mesg, event->resourceid);
  468.         fputs("\n  ", fp);
  469.     }
  470.     } else if ((event->error_code == BadWindow) ||
  471.            (event->error_code == BadPixmap) ||
  472.            (event->error_code == BadCursor) ||
  473.            (event->error_code == BadFont) ||
  474.            (event->error_code == BadDrawable) ||
  475.            (event->error_code == BadColor) ||
  476.            (event->error_code == BadGC) ||
  477.            (event->error_code == BadIDChoice) ||
  478.            (event->error_code == BadValue) ||
  479.            (event->error_code == BadAtom)) {
  480.     if (event->error_code == BadValue)
  481.         XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
  482.                   mesg, BUFSIZ);
  483.     else if (event->error_code == BadAtom)
  484.         XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
  485.                   mesg, BUFSIZ);
  486.     else
  487.         XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
  488.                   mesg, BUFSIZ);
  489.     (void) fprintf(fp, mesg, event->resourceid);
  490.     fputs("\n  ", fp);
  491.     }
  492. #elif (XtSpecificationRelease == 4)
  493.     XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
  494.               mesg, BUFSIZ);
  495.     (void) fprintf(fp, mesg, event->minor_code);
  496.     fputs("\n  ", fp);
  497.     if (ext) {
  498.       sprintf(mesg, "%s.%d", ext->name, event->minor_code);
  499.       XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
  500.       (void) fprintf(fp, " (%s)", buffer);
  501.     }
  502.     XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
  503.               mesg, BUFSIZ);
  504.     (void) fprintf(fp, mesg, event->resourceid);
  505.     fputs("\n  ", fp);
  506. #else
  507. ERROR! Unsupported release of X11
  508. #endif
  509.     XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
  510.     mesg, BUFSIZ);
  511.     (void) fprintf(fp, mesg, event->serial);
  512.     fputs("\n  ", fp);
  513.     XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
  514.     mesg, BUFSIZ);
  515.     (void) fprintf(fp, mesg, NextRequest(dpy)-1);
  516.     fputs("\n", fp);
  517.     if (event->error_code == BadImplementation) return 0;
  518.     return 1;
  519. }
  520.  
  521.  
  522. /*
  523.  * XmuSimpleErrorHandler - ignore errors for XQueryTree, XGetWindowAttributes,
  524.  * and XGetGeometry; print a message for everything else.  In all case, do
  525.  * not exit.
  526.  */
  527. int XmuSimpleErrorHandler (dpy, errorp)
  528.     Display *dpy;
  529.     XErrorEvent *errorp;
  530. {
  531.     switch (errorp->request_code) {
  532.       case X_QueryTree:
  533.       case X_GetWindowAttributes:
  534.         if (errorp->error_code == BadWindow) return 0;
  535.     break;
  536.       case X_GetGeometry:
  537.     if (errorp->error_code == BadDrawable) return 0;
  538.     break;
  539.     }
  540.     /* got a "real" X error */
  541.     return XmuPrintDefaultErrorMessage (dpy, errorp, stderr);
  542. }    
  543.  
  544. void XmuCopyISOLatin1Lowered(char *dst, CONST char *src)
  545. {
  546.     unsigned char *dest, *source;
  547.  
  548.     for (dest = (unsigned char *)dst, source = (unsigned char *)src;
  549.          *source;
  550.          source++, dest++)
  551.     {
  552.         if ((*source >= XK_A) && (*source <= XK_Z))
  553.             *dest = *source + (XK_a - XK_A);
  554.         else if ((*source >= XK_Agrave) && (*source <= XK_Odiaeresis))
  555.             *dest = *source + (XK_agrave - XK_Agrave);
  556.         else if ((*source >= XK_Ooblique) && (*source <= XK_Thorn))
  557.             *dest = *source + (XK_oslash - XK_Ooblique);
  558.         else
  559.             *dest = *source;
  560.     }
  561.     *dest = '\0';
  562. }
  563. #endif /* !HAVE_XMU */
  564.